package com.wyh.service.serviceImpl.gfiveImpl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.protobuf.ServiceException;
import com.wyh.common.enums.ResultCodeEnum;
import com.wyh.common.exception.CustomException;
import com.wyh.common.result.Result;
import com.wyh.common.utils.Md5Util;
import com.wyh.common.utils.RandomUtils;
import com.wyh.common.utils.ali.CaptchaUtil;
import com.wyh.domain.dto.gfive.LoginUser;
import com.wyh.domain.po.gfive.User;
import com.wyh.mapper.gfivemapper.UserMapper;
import com.wyh.security.gfive.service.PermissionsServiceSecurityImpl;
import com.wyh.security.gfive.service.TokenService;
import com.wyh.security.gfive.utils.SecurityUtils;
import com.wyh.service.gfive.RoleService;
import com.wyh.service.gfive.SysLoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

import static com.wyh.common.enums.ResultCodeEnum.CAPTCHA_ERROR;
import static com.wyh.common.enums.ResultCodeEnum.PHONE_ERROR;


/**
 * @author 32276
 * @description 针对登录功能的实现
 * @createDate 2024-05-20 09:55:57
 */
@Service
public class SysLoginServiceImpl extends ServiceImpl<UserMapper, User>
        implements SysLoginService {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Resource
    private AuthenticationManager authenticationManager;


    @Autowired
    private UserMapper userMapper;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private PermissionsServiceSecurityImpl permissionsService;



    @Override
    public String login(String account, String password) {

        if (account != null && password != null) {
            User user = userMapper.findByPhone(account);
            if (user != null) {
                return loginWithTelephonePassword(password, user);
            }
            return loginWithAccountPassword(account, password);
        } else {
            throw new CustomException(ResultCodeEnum.PARAM_ERROR);
        }
    }


    @Override
    public String loginCaptcha(String telephone, int captcha) {

        if (telephone != null && captcha != 0) {
            return loginWithTelephoneCaptcha(telephone, captcha);
        } else {
            throw new IllegalArgumentException("登录信息不完整");
        }

    }

    /*
     * 登录次数验证
     * */
    private void handleFailedLoginAttempt(String account) {
        String redisKey = "failedAttempts:" + account;
        int failedAttempts = Math.toIntExact(redisTemplate.opsForValue().increment(redisKey));
        redisTemplate.expire(redisKey, 24, TimeUnit.HOURS);

        if (failedAttempts >= 5) {
            userMapper.updateState(account);
            throw new CustomException(ResultCodeEnum.USER_LOCKED_ERROR);
        }
    }
    /*
     * 登录成功取消验证
     * */
    private void resetFailedLoginAttempts(String key) {
        String redisKey = "failedAttempts:" + key;
        redisTemplate.delete(redisKey);
    }


    /*
     *
     * 电话密码登录
     * */

    private String loginWithTelephonePassword(String password, User user) {

        if (!Md5Util.getMD5String(password).equals(user.getPassword())) {
            handleFailedLoginAttempt(user.getAccount());
            throw new CustomException(ResultCodeEnum.USER_ACCOUNT_ERROR);
        }
        resetFailedLoginAttempts(user.getAccount());
        LoginUser loginUser = new LoginUser(roleService.selectRoleByUserId(user.getId()), permissionsService.getMenuPermission(user), user);

        // 登录成功后的处理，例如生成JWT token
        return tokenService.loginCreateToken(loginUser);
    }

    /*
     *
     * 账户密码登录
     * */
    private String loginWithAccountPassword(String account, String password) {
        try {
            // 使用Spring Security进行认证
            UsernamePasswordAuthenticationToken authenticationToken =
                    new UsernamePasswordAuthenticationToken(account, Md5Util.getMD5String(password));
            Authentication authentication = authenticationManager.authenticate(authenticationToken);
            SecurityContextHolder.getContext().setAuthentication(authentication);


            LoginUser loginUser = (LoginUser) authentication.getPrincipal();
            resetFailedLoginAttempts(account);
            // 登录成功后的处理，例如生成JWT token

            return tokenService.loginCreateToken(loginUser);
        } catch (AuthenticationException e) {

            handleFailedLoginAttempt(account);
            throw new CustomException(ResultCodeEnum.USER_ACCOUNT_ERROR);

        }
    }

    /*
     *
     * 验证码登录
     * */
    private String loginWithTelephoneCaptcha(String telephone, int captcha) {

        // 加载用户信息
        User user = userMapper.findByPhone(telephone);

        if (user == null) {
            throw new CustomException(ResultCodeEnum.USER_NOT_EXIST_ERROR);
        }

        String redisKey = "captcha" + telephone;
        String redisCode = redisTemplate.opsForValue().get(redisKey);
        if (redisCode == null || !redisCode.equals(String.valueOf(captcha))) {
            handleFailedLoginAttempt(user.getAccount());
            throw new CustomException(CAPTCHA_ERROR);
        }

        resetFailedLoginAttempts(user.getAccount());
        LoginUser loginUser = new LoginUser(roleService.selectRoleByUserId(user.getId()), permissionsService.getMenuPermission(user), user);

        // 登录成功后的处理，例如生成JWT token


        return tokenService.loginCreateToken(loginUser);
    }

    @Override
    public User findByPhone(String phone) {
        return userMapper.findByPhone(phone);
    }


    /*
     * 获取验证码
     * */
    @Override
    public Result sendCaptcha(String phone) {
        User user = findByPhone(phone);
        if (user == null) {
            return Result.error(PHONE_ERROR);
        }

        try {
            int code = Integer.parseInt(RandomUtils.getSixBitRandom());
            String redisCode = String.valueOf(code);

            // 将验证码存入Redis缓存中，有效期为10分钟
            ValueOperations<String, String> operations = redisTemplate.opsForValue();
            operations.set("captcha" + phone, redisCode, 10, TimeUnit.MINUTES);

            // 发送验证码
            CaptchaUtil.createClient();
            CaptchaUtil.CaptchaSend(phone, code);

            return Result.success("验证码发送成功");
        } catch (Exception e) {
            return Result.error(CAPTCHA_ERROR);
        }
    }

    /*
     * 修改密码
     * */

    @Override
    public Result updatePassword(String oldPwd, String newPwd, String rePwd) throws ServiceException {
        if (!StringUtils.hasLength(oldPwd) || !StringUtils.hasLength(newPwd) || !StringUtils.hasLength(rePwd)) {
            return Result.error("缺少必要的参数");
        }

        LoginUser loginUser = SecurityUtils.getLoginUser();
        User user = loginUser.getUser();

        if (!loginUser.getPassword().equals(Md5Util.getMD5String(oldPwd))) {
            return Result.error("原密码填写错误！");
        }

        if (!rePwd.equals(newPwd)) {
            return Result.error("两次密码填写不一致");
        }

        userMapper.updatePwd(Md5Util.getMD5String(newPwd), user.getId());
        tokenService.delLoginUser(loginUser.getToken());

        return Result.success();
    }


}




